package com.bomberdroid.ui;

import java.io.IOException;

import android.app.Activity;
import android.app.ProgressDialog;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.bomberdroid.R;
import com.bomberdroid.protocols.ConnectedThread;
import com.bomberdroid.protocols.Connexion;
import com.bomberdroid.protocols.DataSharing;

public class Client extends Activity {

	private ListView client_listView;
	
	private Connexion connexion;
	private ConnectedThread server;
	
	private ArrayAdapter<String> serversList;
	private ArrayAdapter<String> playersList;
	
	// Create a BroadcastReceiver for ACTION_FOUND when serves are found
	private final BroadcastReceiver receiver = new BroadcastReceiver() {
	    public void onReceive(Context context, Intent intent) {
	        // When discovery finds a device
	        if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
	            // Get the BluetoothDevice object from the Intent
	            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
	            // Add the name and address to an array adapter to show in a ListView to select a server
	            serversList.add((device.getName() + "\n" + device.getAddress()).replace(";", "").replace("&", ""));
	        }
	    }
	};
	
	// Handler to manage communications from server
	private Handler.Callback c = new Handler.Callback() {
		public boolean handleMessage(Message msg) {
			return handleCommunication(msg);
		}
	};
	private Handler handler = new Handler(c);
	
	private ProgressDialog connectingDialog;
	
	// See internal class @ end of file
	private ConnectSocketTask connectSocketTask = new ConnectSocketTask();

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.client);
		
		this.client_listView = (ListView) findViewById(R.id.client_listView);
		
		this.connexion = new Connexion(this);
		this.serversList = new ArrayAdapter<String>(this, android.R.layout.test_list_item);
		this.playersList = new ArrayAdapter<String>(this, android.R.layout.test_list_item);
		this.client_listView.setAdapter(this.serversList);
		this.client_listView.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
	            // when we click on a server in the list, we try to connect the client to it
				connectToServer(((TextView) view).getText().toString().split("\n")[1]);
			}
		});
		
		// Register the BroadcastReceiver
		IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
		this.registerReceiver(receiver, filter);

		// If the bluetooth is enabled, then we start to listen, else we wait for the "onActivityResult()" method to do it
		if(this.connexion.checkBluetooth()){
			this.lookForServer();
		}
	}

	@Override protected void onRestart() {
		super.onRestart();
		this.server.setHandler(this.handler);
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		switch(requestCode){
			case Connexion.REQUEST_ENABLE_BT:
				if(resultCode == RESULT_OK){
					this.lookForServer();
				}
				else{
					Toast.makeText(this.getApplicationContext(), "Bluetooth required.", Toast.LENGTH_LONG).show();
					this.finish();
				}
				break;
		}
	}
	
	/** Start the discovery, servers found are handled bby the BroadcastReceiver */
	private void lookForServer(){
		if(!this.connexion.getBluetoothAdapter().startDiscovery()){
			Toast.makeText(this.getApplicationContext(), "Failed to start discovery.", Toast.LENGTH_LONG).show();
			this.finish();
		}
	}
	
	/** Connect to server and change the content of the list view */
	private void connectToServer(String macAddr){
		// cancel the discovery to releive the Bluetooth adapter
		this.connexion.getBluetoothAdapter().cancelDiscovery();
		try {
        	// Create the server Socket, call connect() via the task, and create the Thread
			BluetoothSocket servSocket = connexion.getBluetoothAdapter().getRemoteDevice(macAddr).createRfcommSocketToServiceRecord(Connexion.uuid);
			this.connectingDialog = ProgressDialog.show(this, "Connecting to "+servSocket.getRemoteDevice().getName(), "Please wait.");
			this.connectSocketTask.execute(servSocket);
			this.server = new ConnectedThread(servSocket, this.handler);
			this.server.start();
		} catch (IOException e) {
			e.printStackTrace();
			Toast.makeText(this.getApplicationContext(), "Enable to use bluetooth.", Toast.LENGTH_LONG).show();
			this.finish();
		}
	}
	
	/** Handles messages from clients comming through ConnectedThread and the Handler */
	private boolean handleCommunication(Message msg){
		boolean res = true;
		String s = new String((byte[])msg.obj, 0, msg.arg1);
		Log.d("Communication", "Client received : "+s);
		String[] messages = s.split("&");
		for(String mess : messages){
			String[] data = mess.split(";");
			if(data[0].equals("z")){
				Toast.makeText(this.getApplicationContext(), "Host server disconnected.", Toast.LENGTH_LONG).show();
				this.finish();
			}else if(data[0].equals("a")){
				
				DataSharing.Client_connexion = this.connexion;
				DataSharing.Client_server = this.server;
				DataSharing.Client_playersList = this.playersList;
				DataSharing.Client_map = Integer.parseInt(data[1]);
				
				Intent myIntent = new Intent(this, ClientGame.class);
				startActivity(myIntent);
			}
			else if(data[0].equals("b")){
				this.playersList.add(data[1]);
			}
			else if(data[0].equals("c")){
				this.playersList.remove(data[1]);
			}
			else{
				res = false;
			}
		}
		return res;
	}

	@Override protected void onDestroy() {
		Log.d("Communication", "Client : Destroying");
		this.unregisterReceiver(receiver);
		// cancel the discovery
		this.connexion.getBluetoothAdapter().cancelDiscovery();
		// Notify the server about leaving
		try{this.server.write("c;"+this.connexion.getIdentity());}catch(Exception e){e.printStackTrace();}
		try{this.server.cancel();}catch(Exception e){e.printStackTrace();}
		super.onDestroy();
	}
	
	/** internal class used to connect the server socket in background */
	private class ConnectSocketTask extends AsyncTask<BluetoothSocket, Boolean, Void> {

		@Override
		protected Void doInBackground(BluetoothSocket... params) {
			try {
				params[0].connect();
				this.publishProgress(true);
			} catch (IOException e) {
				Log.d("Communication", "Sockect connection failed");
				this.publishProgress(false);
				e.printStackTrace();
			}
			return null;
		}

		@Override
		protected void onProgressUpdate(Boolean... values) {
			connectingDialog.dismiss();
			if(values[0]){
				// We change the Text in the text View to display the server we joined.
		    	((TextView)findViewById(R.id.client_text_title)).setText("Joined : "+server.getRemoteDevice().getName());
				// Delete the listener on the view and change its adapter
				client_listView.setOnItemClickListener(null);
				client_listView.setAdapter(playersList);
			}
			else{
				Toast.makeText(getApplicationContext(), "Enable to join server.", Toast.LENGTH_LONG).show();
				finish();
			}
			super.onProgressUpdate(values);
		}
		
	}
}
